git 实践

本文主要是记录 Git 在实际开发中的常见用法和技巧

环境配置(Mac)

1. 检查环境变量

在终端输入 git,如果出现下面的提示,则需要先初始化 xcode

Agreeing to the Xcode/iOS license requires admin privileges, please run “sudo xcodebuild -license” and then retry this command.

打开 Xcode 软件进行初始化即可,之后再次输入’git’,出现下面的提示则说明,环境变量配置成功

usage: git [--version] [--help] [-C <path>] [-c <name>=<value>]
           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
           [-p | --paginate | --no-pager] [--no-replace-objects] [--bare]
           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
           <command> [<args>]

2. 配置用户基本信息

每一条提交都会产生一条记录,这条记录标记了提交人的姓名与邮箱,以便他人查看与联系。

git config --global user.name "JacksonZhou"
git config --global user.email "1359926897@qq.com"
// 查看全局配置
git config --list

3. 配置 ssh

配置了 SSH 到指定服务器上,即说明让服务器信任你的笔记本,每次从 gitlab 或 github 拉代码和上传代码时不用输入用户名和密码

生成 ssh key

ssh-keygen -t rsa -C "1359926897@qq.com"

检查是否生成成功

cat ~/.ssh/id_rsa.pub
// ssh key 生成成功的话,就会看到如下输出
// ssh-rsa ......

复制 ssh-rsa 后面的内容,粘贴到你服务器网站的 SSH Key 配置项里面即完成配置,接下来就可以拉取代码了。

Git 基本操作

先看下 Git 的基本工作流 image.png 下面是一些实际开发过程常见的操作,更详细的内容建议查看 Git 中文手册

工作区 <—> 远程仓库

克隆远程仓库到本地

  • git clone
git clone origin <remote_repo>
git clone -b <branch> <remote_repo> // 从指定分支拉取代码

连接远程仓库

  • git remote
git remote add origin <remote_repo>     // 链接远程仓库
git remote set-url origin <remote_repo> // 修改远程仓库
git remote rm origin                    // 删除远程仓库
git remote -v                           // 查看远程仓库列表
git remote show origin                  // 查看具体仓库细节

upstream

在 Github 上,我们可以 fork 任意开源项目到个人 ID 下,当我们把个人 ID 下的仓库 clone 到本地时,除了默认的 origin 仓库外,我们还需要配置一个 upstream 仓库,指向原始的开源项目地址,保证可以定期同步源仓库的更新。(用的比较少)

git remote add upstream <git_repository_url> // 建立 upstream 仓库
git remote remove upstream                   // 删除远程 upstream 仓库

实际开发过程中,如果没有先确定分支的追踪关系,当我们使用 git pull 或 git push 时就需要指定从远程的哪个分支拉取合并和推送到远程的哪个分支。

git branch -u <> <>    // 指定本地分支和远程分支的追踪关系
git push -u <> <>      // 确定追踪关系并提交代码

与远程仓库同步

  • git pull
git pull origin <branch> // git fetch + git merge,从指定分支拉取代码并更新
git pull --rebase        // git fetch + git rebase,不会生成 merge 记录,建议是用于个人分支

工作区 <—> 暂存区

提交

  • git add
git add .
git add -i // 筛选想要提交的修改并提交

撤销

  • git restore

暂存区 <—> 本地仓库

提交

  • git commit
git commit -m "" // 提交代码到本地仓库

重新提交

如果发现已经提交了改动,但是还有修改也是需要合到那一部分改动中的,可以这样操作

git add .
git commit --amend -m ""
// amend 也可以单纯用来修改 commit 信息

撤销

  • git reset - 适用于本地记录,即还没提交到远程仓库的记录
git reset HEAD^1 --hard   // 重置为上一个 commit,并清空工作区域的代码改动
git reset HEAD^1 --soft   // 重置为上一个 commit,不过会保留工作区域的代码改动
  • git revert - 适用于已经提交到远程仓库的记录的撤销

commit message 规范

# 主 type
feat:     增加新功能
fix:      修复bug

# 其他 type
docs:     只改动了文档相关的内容
style:    不影响代码含义的改动,例如去掉空格、改变缩进、增删分号
build:    构造工具的或者外部依赖的改动,例如webpack,npm
refactor: 代码重构时使用
revert:   执行git revert打印的message
test:     添加测试或者修改现有测试
perf:     提高性能的改动
ci:CI(持续集成服务)有关的改动
chore:    不修改src或者test的其余修改,例如构建过程或辅助工具的变动

本地仓库 <—> 远程仓库

同步

  • git fetch
  1. 从远程仓库下载本地仓库中缺失的提交记录
  2. 更新远程分支指针

提交

  • git push

    在多人协作的分支上尽量不用 git push -f、git rebase、reset 的操作

git push -f.gif

撤销

HEAD

HEAD 总是指向当前分支上最近一次提交记录。

git checkout <commit_hash> // 让 HEAD 指向指定的 commit
HEAD^  // 向前移动一个提交记录
HEAD^2 // TODO 移动到前面一排记录的第二个提交记录
HEAD~3 // 向前提交三个记录

通过 cat .git/head 可以查看 HEAD 指向

分支

  • git branch - 创建本地分支
git branch '' // 创建分支
git switch '' // 切换分支
git checkout -b '' // 创建分支并切换到该分支
git branch -f <branch> <commit_hash/branch> // 将指定 branch 的 HEAD 指向某个提交记录或者某个分支的 HEAD

stash

git stash 可以将当前工作状态(WIP,work in progress)临时存放在 stash 列表中,待 pull / merge 操作完成后,再从 stash 中重新应用这些修改。

git stash list
git stash save 'message' // 存储一个自定义 message 的 WIP 到 stash 栈中
git stash -u save '' // -u 参数表明新增的文件也一起 stash
git stash pop // 恢复上一次的 WIP 状态,并从 stash 栈中移除
git stash pop stash@{num}   // 恢复指定编号的 WIP,并从 stash 栈中移除
git stash apply stash@{num}  // 恢复指定编号的 WIP,但不从 stash 栈中移除

如果 git stash 的文件刚好被其他提交修改过了,那么在 pop 时会自动将修改过的文件标记为 conflict 状态

合并代码

merge

该命令主要按以下两种策略合并代码:

Fast-forword(—ff)

git_merge_ff.gif

no-fast-forword(—no-ff)

git_merge_noff.gif

rebase

Rebase 实际上就是取出一系列的提交记录,将他们复制到其他地方。相比 merge,rebase 能提供更加线性的提交历史。这个操作比较危险,会改变提交历史,因此建议不要对已经处于远端的多人共用分支做 rebase 操作。

reword:修改提交信息;
edit:修改此提交;
squash:将提交融合到前一个提交中;
fixup:将提交融合到前一个提交中,不保留该提交的日志消息;
exec:在每个提交上运行我们想要 rebase 的命令;
drop:移除该提交。

git_rebase.gif

复制记录

  • cherry-pick - 可以复制指定的 commit

查看日志

  • git config
// 1. git 配置 alias
git config --global alias.ls 'log --name-status --oneline --graph'
git ls
git config --global alias.lg "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative"
git lg
// 2. 用 zsh 配置 alias

git show <commit_id> // 查看具体某次commit记录
git log -p -n // n是代表最近几次的提交,可以查看最近几次commit记录

开发实践

合并多个 commit

  • git rebase -i HEAD~3 // 编辑最近三个记录
p HEAD1
s HEAD2
s HEAD3

如何修改之前的某个提交(已 push)?

  1. git rebase 先调整待修改的提交到最新
  2. 修改后提交
  3. git rebase 再调整回来

如何修改之前的某个 commit?

  • git commit --amend — 修改 commit message 或追加文件改动建议用这个
  • git reset HEAD^1 --soft

如何复制其他分支的文件夹到当前分支?

git checkout <branch> -- [file_name]

参考